﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace Aleator.Core.Techniques
{
    /// <summary>
    /// Base class for insatrument techniques
    /// </summary>
    public class Technique
    {
        #region Members

        private static readonly Technique m_instance = new Technique();

#pragma warning disable 1591

        protected static NoteFactory m_notefactory = new ConcreteNoteFactory();

        protected static ContinuousUniformDistribution m_continuous = new ContinuousUniformDistribution();
        protected static NormalDistribution m_normal = new NormalDistribution();
        protected static RayleighDistribution m_rayleigh = new RayleighDistribution();

        protected static int m_location;
        protected static int m_measure;

#pragma warning restore 1591

        #endregion

        public enum TechniqueType
        {
            Bounce,
            Vibe,
            Rock
        }

        #region Constructor

        static Technique() { }

        #endregion

        #region Methods

        /// <summary>
        /// BounceGenerator instance
        /// </summary>
        public static Technique Instance
        {
            get
            {
                return m_instance;
            }
        }

        /// <summary>
        /// Fill the phrase with notes
        /// </summary>
        public virtual void Generate(ConcretePhrase p) { }

        /// <summary>
        /// Get note totas for the phrase
        /// </summary>
        /// <param name="totalmeasures">Total measures for the phrase</param>
        /// <param name="target">Mu value for distribution object</param>
        /// <returns></returns>
        protected virtual int GetTotal(int totalmeasures, double target) 
        {
            //Use normal distribution to calculate drum note totals
            m_normal.Mu = target;
            m_normal.Sigma = 2.0;

            double next = 0.0;
            int intnext = 0;

            while (Convert.ToInt32(next) <= 0)
                next = m_normal.NextDouble();

            intnext = (int)next;

            //This ensures that there is at least one of each in every measure. Will probably need to change this later.
            if (intnext < totalmeasures)
                return totalmeasures;
            else
                return intnext;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="p"></param>
        protected virtual void SetTotals(Phrase p) { }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="dp"></param>
        /// <param name="t"></param>
        protected virtual void GetBeat(DrumPhrase dp, DrumPhrase.Type t)
        {
            int res;

            if (t == DrumPhrase.Type.Kick)
                res = dp.KickResolution;
            else if (t == DrumPhrase.Type.Snare)
                res = dp.SnareResolution;
            else
                res = dp.HiHatResolution;

            int playablenotesinmeasure = dp.Progression.Numerator * res;

            //Pick a distribution generator based on phrase XML
            if (dp.PhraseRhythm.Distribution == "Uniform")
            {
                m_location = Math.Min((int)Math.Round(m_continuous.NextDouble()), playablenotesinmeasure - 1);
            }
            else
            {
                m_location = Math.Min((int)Math.Round((m_rayleigh.NextDouble() / 10) * playablenotesinmeasure),
                    playablenotesinmeasure - 1);

                //If this phrase is wieghted to the back, we have to take flip the beat value
                if (dp.PhraseRhythm.Distribution == "Back")
                {
                    m_location = playablenotesinmeasure - m_location - 1;
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="p"></param>
        protected virtual void GetBeat(Phrase p){ }

        #endregion

    }
}
